-- ===========================
-- Load in the SavedVariables saved by the World of Wacraft client.
-- The data is contained in the OrunjSave table. What we want here is to
-- make one data file per session.
-- ===========================
-- dofile("Orunj.lua")
-- dofile("C:\\Program Files (x86)\\World of Warcraft\\Interface\\AddOns\\Orunj\\TestRuns\\07.16.10@19-23-53\\07.16.10@19-23-53.lua")
dofile("../../../../WTF/Account/MARTIEN89/SavedVariables/Orunj.lua")

-- Import the Love Exporting 
dofile("LoveExport.lua")

-- Import the Orunj Analysis file
dofile("OrunjAnalyze.lua")

OrunjSave = OrunjSave or { sessions = {} }

-- local dataFileExtension = ".txt"
-- local gnuplotScriptFileExtension = ".p"
dofile("formats.lua")

-- ===========================
-- Serialize a session table, as per [http://www.lua.org/pil/12.1.1.html]
-- ===========================
local function serialize(o)
	if type(o) == "number" then
		io.write(o)
	elseif type(o) == "string" then
		io.write(string.format("%q", o))
	elseif type(o) == "boolean" then
		io.write(tostring(o))
	elseif type(o) == "table" then
		io.write("{\n")
		for k,v in pairs(o) do
			io.write("  [")
        	serialize(k)
        	io.write("] = ")
			serialize(v)
			io.write(",\n")
		end
		io.write("}\n")
	else
		error("cannot serialize a " .. type(o))
	end
end

-- ===========================
-- Export a session
-- ===========================
local function ExportRawSession(directory, outputFilename, sessionName, session)
	local filename = outputFilename .. extensions.lua
	local path = directory .. "/" .. filename
	local file = io.open(path, "w")
	io.output(file)
	
	io.write("OrunjSave = { sessions = { [\"" .. sessionName .. "\"] = ")
	serialize(session)
	io.write("}\n}\n")
	
	file:close()
end


-- ===========================
-- Export the session using the session name.
-- ===========================
local function CreateHealthPowerDataFile(directory, sessionFilename, session)
	-- Open the file.
	local filename = sessionFilename .. extensions.data
	local path = directory .. "/"  .. filename
	local dataFile = io.open(path, "w")
	io.output(dataFile)
	
	-- Write to the file in a space-seperated vector format.
	-- #UnitHealth1 UnitPower1 UnitHealth2 UnitPower2 ..
	-- Set up the identification for each player.
	io.write("#SequenceNumber ")
	for k, v in pairs (session.players) do
		local name = session.players[k].name
		io.write(name .. "_UnitHealth" .. " " .. name .. "_UnitPower" .. " ")
	end
	io.write("\n")
	
	-- Write the unit data for each sequence number.
	local numLines = session.sequenceNumber - 1
	for i = 1, numLines do
		-- Write the sequence number at the beginning of the line.
		io.write(tostring(i) .. " ")
		-- For each player, write his UnitHealth and UnitPower.
		for k, v in pairs(session.players) do
			local timelines = session.players[k].timelines
			local unitHealth = timelines.unitHealthTimeline
			local unitPower = timelines.unitPowerTimeline
			io.write(unitHealth[i] .. " " .. unitPower[i] .. " ")
		end
		io.write("\n")
	end 
	
	-- close the file.
	dataFile:close()
end

-- ===========================
-- Create the gnuplot script associated with the session.
-- ===========================
local function CreateHealthPowerGnuplotScript(directory, sessionFilename, outputFilename, format, session)
	-- Open the file.
	local filename = outputFilename .. extensions.gnuplot
	local path = directory .. "/"  .. filename
	local gnuplotScriptFile = io.open(path, "w")
	io.output(gnuplotScriptFile)
	
	-- Write the titles and labels
	io.write("#Orunj Recording session: " .. sessionFilename .. "\n")
	io.write("reset\n")
	if format then
		-- redirect output to the specified place
		io.write("set terminal " .. format.name .. "\n")
		io.write("set output \"" .. sessionFilename .. format.extension .. "\"\n")
	else
		-- defaults
		io.write("set terminal wxt\n") -- wxt is a nice window terminal.
		io.write("set output\n")
	end
	io.write("set autoscale\n")
	io.write("set title \"Player Health and Power\"\n")
	io.write("set xlabel \"Sequence number\"\n")
	io.write("set ylabel \"Unit Data\"\n")
	
	-- HealthPower plot
	local sequenceColumn = 1
	local currentPlayerColumn = 2
	local healthIndex = 1
	local powerIndex = 2
	local columnOffsets = {[healthIndex] = 0, [powerIndex] = 1}
	local first = true
	io.write("plot ")
	for k,v in pairs(session.players) do
		-- Make sure we have commas seperating the entries after the first entry.
		if not first then
			io.write(" , ")
		end
		
		-- Health column for the player.
		io.write("\"" .. sessionFilename .. extensions.data .. "\" ")
		io.write("using " .. tostring(sequenceColumn))
		io.write(":" .. tostring(currentPlayerColumn + columnOffsets[healthIndex]) .. " ")
		io.write("title '" .. v.name .. " (" .. v.class .. " - " .. tostring(v.role) .. ") Health' ")
		io.write("with lines , ")
		
		-- Power column for the player.
		io.write("\"" .. sessionFilename .. extensions.data .. "\" ")
		io.write("using " .. tostring(sequenceColumn))
		io.write(":" .. tostring(currentPlayerColumn + columnOffsets[powerIndex]) .. " ")
		io.write("title '" .. v.name .. " (" .. v.class .. " - " .. tostring(v.role) .. ") Power' ")
		io.write("with lines")
		
		currentPlayerColumn = currentPlayerColumn + #columnOffsets
		first = false		
	end
	io.write("\n")
	io.write("set output\n")
	
	-- close the file.
	gnuplotScriptFile:close()
	return filename
end

-- ===========================
-- Health-only plot.
-- ===========================
local function CreateHealthGnuplotScript(directory, sessionFilename, outputFilename, format, session)
	-- Open the file.
	local filename = outputFilename .. extensions.gnuplot
	local path = directory .. "/"  .. filename
	local gnuplotScriptFile = io.open(path, "w")
	io.output(gnuplotScriptFile)
	
	-- Write the titles and labels
	io.write("#Orunj Recording session: " .. sessionFilename .. "\n")
	io.write("reset\n")
	if format then
		-- redirect output to the specified place
		io.write("set terminal " .. format.name .. "\n")
		io.write("set output \"" .. outputFilename .. format.extension .. "\"\n")
	else
		-- defaults
		io.write("set terminal wxt\n") -- wxt is a nice window terminal.
		io.write("set output\n")
	end
	io.write("set autoscale\n")
	io.write("set title \"Player Health\"\n")
	io.write("set xlabel \"Sequence number\"\n")
	io.write("set ylabel \"Unit Data\"\n")
	
	-- HealthPower plot
	local sequenceColumn = 1
	local currentPlayerColumn = 2
	local healthIndex = 1
	local powerIndex = 2
	local columnOffsets = {[healthIndex] = 0, [powerIndex] = 1}
	local first = true

	-- Health-Only plot.
	io.write("plot ")
	first = true
	currentPlayerColumn = 2
	for k,v in pairs(session.players) do
		-- Make sure we have commas seperating the entries after the first entry.
		if not first then
			io.write(" , ")
		end
		
		-- Health column for the player.
		io.write("\"" .. sessionFilename .. extensions.data .. "\" ")
		io.write("using " .. tostring(sequenceColumn))
		io.write(":" .. tostring(currentPlayerColumn + columnOffsets[healthIndex]) .. " ")
		io.write("title '" .. v.name .. " (" .. v.class .. " - " .. tostring(v.role) .. ") Health' ")
		io.write("with lines ")
		
		currentPlayerColumn = currentPlayerColumn + #columnOffsets
		first = false		
	end
	io.write("\n")
	io.write("set output\n")
	
	-- close the file.
	gnuplotScriptFile:close()
	return filename
end

-- ===========================
-- Power-only plot
-- ===========================
local function CreatePowerGnuplotScript(directory, sessionFilename, outputFilename, format, session)
	-- Open the file.
	local filename = outputFilename .. extensions.gnuplot
	local path = directory .. "/"  .. filename
	local gnuplotScriptFile = io.open(path, "w")
	io.output(gnuplotScriptFile)
	
	-- Write the titles and labels
	io.write("#Orunj Recording session: " .. sessionFilename .. "\n")
	io.write("reset\n")
	if format then
		-- redirect output to the specified place
		io.write("set terminal " .. format.name .. "\n")
		io.write("set output \"" .. outputFilename .. format.extension .. "\"\n")
	else
		-- defaults
		io.write("set terminal wxt\n") -- wxt is a nice window terminal.
		io.write("set output\n")
	end
	io.write("set autoscale\n")
	io.write("set title \"Player Power\"\n")
	io.write("set xlabel \"Sequence number\"\n")
	io.write("set ylabel \"Unit Data\"\n")
	
	-- HealthPower plot
	local sequenceColumn = 1
	local currentPlayerColumn = 2
	local healthIndex = 1
	local powerIndex = 2
	local columnOffsets = {[healthIndex] = 0, [powerIndex] = 1}
	local first = true

	-- Mana-Only plot.
	io.write("plot ")
	first = true
	currentPlayerColumn = 2
	for k,v in pairs(session.players) do
		-- Make sure we have commas seperating the entries after the first entry.
		if not first then
			io.write(" , ")
		end
		
		-- Power column for the player.
		io.write("\"" .. sessionFilename .. extensions.data .. "\" ")
		io.write("using " .. tostring(sequenceColumn))
		io.write(":" .. tostring(currentPlayerColumn + columnOffsets[powerIndex]) .. " ")
		io.write("title '" .. v.name .. " (" .. v.class .. " - " .. tostring(v.role) .. ") Power' ")
		io.write("with lines")
		
		currentPlayerColumn = currentPlayerColumn + #columnOffsets
		first = false		
	end
	io.write("\n")
	io.write("set output\n")
	
	-- close the file.
	gnuplotScriptFile:close()
	return filename
end

-- ===========================
-- Export the player position data into text files according to maps.
-- Also handles the MEC calculation
-- ===========================
local function CreatePositionDataFile(directory, sessionFilename, session)
	-- Reverse the maps
	local mapTimeline = session.globalTimelines.mapTimeline
	local maps = {}
	
	-- Explore both the dictionary and the index portions of the table
	-- as seen at the bottom of http://www.lua.org/pil/4.3.5.html
	for k, map in pairs(mapTimeline) do maps[map] = {} end
	for i, map in ipairs(mapTimeline) do maps[map] = {} end
	
	-- Create file handles for each map visited, and set up the comments for each column. 
	local files = {}
	for map in pairs(maps) do
		local filename = sessionFilename .. tostring(map) .. extensions.data
		local path = directory .. "/"  .. filename
		files[map] = io.open(path, "w")
		-- Set the current output to the file.
		io.output(files[map])
		
		-- Write the map name to identify the area.
		io.write("#Map: " .. tostring(map) .. "\n")
		
		-- Identify the sequence number column.
		io.write("#SequenceNumber ")
		
		-- Identify the player columns.
		for k,v in pairs (session.players) do
			local name = session.players[k].name
			io.write(name .. "_x " .. name .. "_y ")
		end
		io.write("\n")
	end
	
	-- Sequentially write the position of each player, making sure to switch
	-- maps when necessary.
	local previousMap = nil
	-- Write the unit data for each sequence number.
	local numLines = session.sequenceNumber - 1
	for i = 1, numLines do
		-- 1. Check if we have to change our file output.
		local currentMap = mapTimeline[i] -- If currentMap is nil, then we don't have to do anything.
		if currentMap and currentMap ~= previousMap then
			-- Switch the output to the appropriate file.
			io.output(files[currentMap])
			-- Insert the current sequence number "i" into the current map table,
			-- and the previous sequence number into the previous map table,
			-- to denote a break.
			if previousMap then	table.insert(maps[previousMap], i-1) end
			table.insert(maps[currentMap], i)
			-- Set the previous map to the current map.
			previousMap = currentMap
		end
		
		-- Make sure we record the very last sequence number in the current map.
		if i == numLines then
			table.insert(maps[previousMap], i)
		end
		
		-- 2. Proceed to write the data.
		-- Write the sequence number at the beginning of the line.
		io.write(tostring(i) .. " ")
		-- For each player, write his x and y position.
		for k, v in pairs(session.players) do
			-- Retrieve the x and y positions.
			local timelines = session.players[k].timelines
			local x = timelines.xPositionTimeline[i]
			local y = timelines.yPositionTimeline[i]
			
			-- Prefix the point with a "?" to tell gnuplot to ignore it when plotting,
			-- since (0,0) is usually an invalid position.
			if x == 0 then x = "?" .. tostring(x) end
			if y == 0 then y = "?" .. tostring(y) end
			
			-- Write it to the file.
			io.write(tostring(x) .. " " .. tostring(y) .. " ")
		end
		io.write("\n")
	end
	
	-- Close all the open files.
	for mapname, file in pairs(files) do
		file:close()
	end
	
	-- Return the table of all the maps appearing in the session.
	return maps
end

-- ===========================
-- Create the Gnuplot script to plot the player position data according to each map visited.
-- ===========================
local function CreatePositionGnuplotScript(directory, sessionFilename, outputFilename, format, session, maps)
	-- Open the file.
	local filename = outputFilename .. extensions.gnuplot
	local path = directory .. "/"  .. filename
	local gnuplotScriptFile = io.open(path, "w")
	io.output(gnuplotScriptFile)
	
	-- Write the titles and labels
	io.write("#Orunj Recording session: " .. sessionFilename .. "\n")
	io.write("reset\n")
	-- Make one plot per map.
	for map, breakTable in pairs(maps) do
		-- Get the data filename.
		local dataFilename = sessionFilename .. tostring(map) .. extensions.data
		
		-- Format before we plot.
		if format then
			-- redirect output to the specified place
			io.write("set terminal " .. format.name .. "\n")
			io.write("set output \"" .. sessionFilename .. tostring(map) .. format.extension .. "\"\n")
		else
			-- defaults
			io.write("set terminal wxt\n") -- wxt is a nice window terminal.
			io.write("set output\n")
		end
		
		-- Set the scale and labels.
		io.write("set title \"Player position on " .. tostring(map) .. "\"\n")
		io.write("set autoscale\n")
		--io.write("set xrange [0:1]\n")
		--io.write("set yrange [0:1]\n")
		io.write("set xlabel \"x position\"\n")
		io.write("set ylabel \"y position\"\n")
		
		-- Get the local player.
		local localPlayer = nil
		for guid, player in pairs(session.players) do
			if player.me == true then
				localPlayer = player
				break
			end
		end
		
		-- Label all the transitions and their sequence number.
		io.write("unset label\n")
		if localPlayer then
			for i, sequenceNumber in ipairs(breakTable) do
				local x = localPlayer.timelines.xPositionTimeline[sequenceNumber]
				local y = localPlayer.timelines.yPositionTimeline[sequenceNumber]
				io.write("set label \"Sequence#: " .. tostring(sequenceNumber) .. "\" at " .. tostring(x) .. "," .. tostring(y) .. "\n")
			end
		end		
		
		local currentPlayerColumn = 2
		local xIndex = 1
		local yIndex = 2
		local columnOffsets = {[xIndex] = 0, [yIndex] = 1}
		local first = true
		io.write("plot ")
		for k,v in pairs(session.players) do
			-- Make sure we have commas seperating the entries after the first entry.
			if not first then
				io.write(" , ")
			end
			
			-- Health column for the player.
			io.write("\"" .. dataFilename .. "\" ")
			io.write("using " .. tostring(currentPlayerColumn + columnOffsets[xIndex]))
			io.write(":" .. tostring(currentPlayerColumn + columnOffsets[yIndex]) .. " ")
			io.write("title '" .. v.name .. " (" .. v.class .. " - " .. tostring(v.role) .. ") Position' ")
			--io.write("with linespoints ")
			io.write("with lines ")
			
			currentPlayerColumn = currentPlayerColumn + #columnOffsets
			first = false		
		end			
		io.write("\n")
		io.write("set output\n")
	end
	
	-- close the script.
	gnuplotScriptFile:close()
	return filename
end

-- ===========================
-- Create a global gnuplot script that loads every other script related to this session.
-- ===========================
local function CreateGlobalGnuplotScript(directory, sessionName, filenames)
	-- Open the file.
	local filename = directory .. "/"  .. sessionName .. extensions.gnuplot
	local gnuplotScriptFile = io.open(filename, "w")
	io.output(gnuplotScriptFile)
	io.write("#Orunj Recording session: " .. sessionName .. "\n")
	for i, filename in ipairs(filenames) do
		io.write("load '" .. filename .. "'\n")
	end
	gnuplotScriptFile:close()
end

-- ===========================
-- Main program
-- ===========================
local function Main()
	-- If OrunjSave doesn't exist, return.
	if not OrunjSave then return end
	
	-- Iterate over each session in OrunjSave.
	for k, v in pairs(OrunjSave.sessions) do
		-- Change the name so it's valid.
		local sessionName = string.gsub(string.gsub(string.gsub(k, "/", "."), ":", "-"), " ", "@")
		local directory = sessionName
		os.execute("mkdir " .. directory)
		
		-- The scripts to keep track of
		local sessionScripts = {}
		
		-- A temporary variable used to grab outputted filenames.
		local f
		
		-- Export the single session data.
		ExportRawSession(directory, sessionName, k, v)
		
		-- HealthPower data script
		CreateHealthPowerDataFile(directory, sessionName .. filenameSuffixes.healthPower, v)
		f = CreateHealthPowerGnuplotScript(directory, sessionName .. filenameSuffixes.healthPower, sessionName .. filenameSuffixes.healthPower, formats.pdf, v)
		if f then table.insert(sessionScripts, f) end
		
		f = CreateHealthGnuplotScript(directory, sessionName .. filenameSuffixes.healthPower, sessionName .. filenameSuffixes.health, formats.pdf, v)
		if f then table.insert(sessionScripts, f) end
		
		f = CreatePowerGnuplotScript(directory, sessionName .. filenameSuffixes.healthPower, sessionName .. filenameSuffixes.power, formats.pdf, v)
		if f then table.insert(sessionScripts, f) end
		
		CreateIntensityDataFile(directory, sessionName .. filenameSuffixes.intensity, v)
		f = CreateIntensityGnuplotScript(directory, sessionName .. filenameSuffixes.intensity, sessionName .. filenameSuffixes.intensity, formats.pdf, v)
		if f then table.insert(sessionScripts, f) end
		
		-- Position data script.
		local maps = CreatePositionMECDataFile(directory, sessionName .. filenameSuffixes.position, v)
		f = CreatePositionMECGnuplotScript(directory, sessionName .. filenameSuffixes.position, sessionName .. filenameSuffixes.position, formats.pdf, v, maps)
		if f then table.insert(sessionScripts, f) end
		
		-- Create a global gnuplot script for this session.
		CreateGlobalGnuplotScript(directory, sessionName, sessionScripts)
		
		-- Export the Love session so it can be replayed in the Love framework.
		LoveExport(directory, sessionName)
		
	end
end

-- Run the main program.
Main()
